package net.beyondts.mplug.utils;

import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Project: mplug-project<br/>
 * Description: <br/>
 * Created at: 2019-1-12<br/>
 * Owned by beyondts.
 *
 * @author blazecrystal
 * @version 1.0.0
 */
public class JarUtils {
    /**
     * 获得jar包中所有的类名称（全名）.
     *
     * @param jar {@link String} jar文件全路径
     * @return {@link List}&lt;{@link String}&gt; 类全名列表
     * @throws IOException jar文件不存在或者无法解析
     */
    public static List<String> getAllClassNames(String jar) throws IOException {
        List<String> nameList = new ArrayList<String>();
        JarFile file = null;
        try {
            file = new JarFile(jar);
            Enumeration<JarEntry> entries = file.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String tmp = entry.getName().toLowerCase();
                if (tmp.endsWith(".class")) {
                    int dotIndex = tmp.lastIndexOf(".class");
                    nameList.add(Transformer.toLocalFilePath(
                            entry.getName().substring(0, dotIndex)).replace(
                            File.separator, "."));
                }
            }
        } finally {
            IOUtils.closeQuietly(file);
        }
        return nameList;
    }

    /**
     * 获得jar包中所有的类名称（全名）.
     *
     * @param jar {@link File} jar文件
     * @return {@link List}&lt;{@link String}&gt; 类全名列表
     * @throws IOException jar文件不存在或者无法解析
     */
    public static List<String> getAllClassNames(File jar) throws IOException {
        return getAllClassNames(jar.getAbsolutePath());
    }

    /**
     * 获得jar包中所有的类名称（全名）.
     *
     * @param jars {@link String}[] jar文件绝对路径
     * @return {@link List}&lt;{@link String}&gt; 类全名列表
     * @throws IOException jar文件不存在或者无法解析
     */
    public static List<String> getAllClassNames(String[] jars)
            throws IOException {
        List<String> nameList = new ArrayList<String>();
        for (String jar : jars) {
            nameList.addAll(getAllClassNames(jar));
        }
        return nameList;
    }

    /**
     * 获得jar包中所有的类名称（全名）.
     *
     * @param jars {@link File}[] jar文件
     * @return {@link List}&lt;{@link String}&gt; 类全名列表
     * @throws IOException jar文件不存在或者无法解析
     */
    public static List<String> getAllClassNames(File[] jars) throws IOException {
        List<String> nameList = new ArrayList<String>();
        for (File jar : jars) {
            nameList.addAll(getAllClassNames(jar.getAbsolutePath()));
        }
        return nameList;
    }

    public static List<String> getBaseScanPackage(File jar) throws IOException {
        List<String> packages = new ArrayList<>();
        JarFile jarFile = null;
        try {
            jarFile = new JarFile(jar);
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (entry.isDirectory()) {
                    packages.add(entry.getName());
                }
            }
        } finally {
            IOUtils.closeQuietly(jarFile);
        }
        return packages;
    }

    public static List<Class<?>> getComponentAnnotatedClasses(File jar, ClassLoader loader) throws IOException, ClassNotFoundException {
        List<String> classNames = getAllClassNames(jar);
        List<Class<?>> classes = new ArrayList<>();
        for (String className : classNames) {
            Class<?> clazz = Class.forName(className, false, loader);
            if (clazz.getAnnotation(Component.class) != null) {
                classes.add(clazz);
            }
        }
        return classes;
    }
}
